package com.shujia.scala

object Demo08Func04 {

  def main(args: Array[String]): Unit = {
    /**
     * 函数可以定义在哪里？
     * 1、定义在方法中，例如：main方法或者是其它普通的方法
     * 2、定义在object中，默认会有静态的特性，可以通过类对象进行调用
     * 3、定义在class中，普通的成员方法，需要通过类的对象进行调用
     */

    // 面向函数编程之以函数作为返回值

    def funcX1(i1: Int): (String, Int) => Int = {
      // (String,Int)=>Int
      def f(s1: String, i2: Int): Int = {
        i1 + s1.toInt + i2 + 100
      }

      f
    }

    // 简化定义
    def funcX2(i1: Int)(s1: String, i2: Int): Int = {
      // (String,Int)=>Int
      i1 + s1.toInt + i2 + 100
    }


    // 参数在定义是可以附上默认值，即默认参数
    def funcX3(i1: Int)(s1: String = "100", i2: Int = 100): Int = {
      // (String,Int)=>Int
      i1 + s1.toInt + i2 + 100
    }

    // 柯里化函数：将有N个参数的函数变成N个只有一个参数的函数
    def sourceFunc(i1: Int, i2: Int, i3: Int, i4: Int, i5: Int): String = {
      (i1 + i2 + i3 + i4 + i5).toString
    }

    def sourceFuncKeLiHua(i1: Int)(i2: Int)(i3: Int)(i4: Int)(i5: Int): String = {
      (i1 + i2 + i3 + i4 + i5).toString
    }

    // 偏应用函数：将有N个参数的函数变成有N-M个参数的函数，M表示固定参数的个数
    def sourceFunc02(i1: Int, i2: Int, i3: Int, i4: Int, i5: Int): String = {
      (i1 + i2 + i3 + i4 + i5).toString
    }

    def sourceFunc02PianYingYong(i1: Int, i2: Int, i3: Int, i4: Int = 4, i5: Int = 5): String = {
      (i1 + i2 + i3 + i4 + i5).toString
    }

    // funcX1的调用
    // 分步调用
    val func: (String, Int) => Int = funcX1(10)
    val res: Int = func("20", 30)
    println(res) // 160

    // 直接调用
    println(funcX1(10)("20", 30)) // 160
    println(funcX2(10)("20", 30)) // 160
    println(funcX3(10)("20", 30)) // 160
    println(funcX3(10)()) // 310
    println(funcX3(10)(i2 = 200)) // 410


    println(sourceFunc(1, 2, 3, 4, 5))
    println(sourceFuncKeLiHua(1)(2)(3)(4)(5))
    println(sourceFunc02(1,2,3,4,5))
    println(sourceFunc02PianYingYong(1,2,3,4,5))
    println(sourceFunc02PianYingYong(1,2,3,4))
    println(sourceFunc02PianYingYong(1,2,3))
  }

}
